#ifndef __IVARIANT_HELPER_H__
#define __IVARIANT_HELPER_H__

#include "exceptions.h"
#include "ref_obj_ptr.h"


namespace Boss
{

  BOSS_DECLARE_RUNTIME_EXCEPTION(IVariantHelper)

  class IVariantHelper
  {
  public:
    typedef RefObjPtr<IVariant> IVariantPtr;

    IVariantHelper(IVariantPtr var)
      : Var(var)
    {
      if (!Var.Get())
        throw IVariantHelperException("Empty variant pointer");
    }
    IVariantHelper(IVariant *var)
      : Var(var)
    {
      if (!Var.Get())
        throw IVariantHelperException("Empty variant pointer");
    }
    ~IVariantHelper()
    {
    }

    IVariantHelper& operator = (bool value)
    {
      Var->SetValue(IVariant::vtBool, &value);
      return *this;
    }
    IVariantHelper& SetBinaryData(const TPtr data, ULong bytes)
    {
      Var->SetBinaryValue(data, bytes);
      return *this;
    }
    IVariantHelper& operator = (IBase *ptr)
    {
      Var->SetValue(IVariant::vtIBase, ptr);
      return *this;
    }
    IVariantHelper& operator = (char value)
    {
      Var->SetValue(IVariant::vtChar, &value);
      return *this;
    }
    IVariantHelper& operator = (unsigned char value)
    {
      Var->SetValue(IVariant::vtUChar, &value);
      return *this;
    }
    IVariantHelper& operator = (short value)
    {
      Var->SetValue(IVariant::vtShort, &value);
      return *this;
    }
    IVariantHelper& operator = (unsigned short value)
    {
      Var->SetValue(IVariant::vtUShort, &value);
      return *this;
    }
    IVariantHelper& operator = (int value)
    {
      Var->SetValue(IVariant::vtInt, &value);
      return *this;
    }
    IVariantHelper& operator = (unsigned int value)
    {
      Var->SetValue(IVariant::vtUInt, &value);
      return *this;
    }
    IVariantHelper& operator = (long value)
    {
      Var->SetValue(IVariant::vtLong, &value);
      return *this;
    }
    IVariantHelper& operator = (unsigned long value)
    {
      Var->SetValue(IVariant::vtULong, &value);
      return *this;
    }
    IVariantHelper& operator = (float value)
    {
      Var->SetValue(IVariant::vtFloat, &value);
      return *this;
    }
    IVariantHelper& operator = (double value)
    {
      Var->SetValue(IVariant::vtDouble, &value);
      return *this;
    }
    IVariantHelper& operator = (const char *value)
    {
      Var->SetValue(IVariant::vtString, (const TPtr)(value));
      return *this;
    }
    IVariantHelper& operator = (const wchar_t *value)
    {
      Var->SetValue(IVariant::vtWString, (const TPtr)(value));
      return *this;
    }

    operator const bool () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtBool)
        throw IVariantHelperException("Bad cast");
      bool *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const TPtr () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtBinary)
        throw IVariantHelperException("Bad cast");
      TPtr Value = 0;
      if (!GetDataSize())
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(&Value) != rcOk)
        throw IVariantHelperException("Can't get value");
      return Value;
    }
    operator RefObjPtr<IBase> () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtIBase)
        throw IVariantHelperException("Bad cast");
      RefObjPtr<IBase> Value;
      if (GetDataSize() != sizeof(Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(Value.GetPPtr())) != rcOk)
        throw IVariantHelperException("Can't get value");
      return Value;
    }
    operator const char () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtChar)
        throw IVariantHelperException("Bad cast");
      char *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const unsigned char () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtUChar)
        throw IVariantHelperException("Bad cast");
      unsigned char *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const short () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtShort)
        throw IVariantHelperException("Bad cast");
      short *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const unsigned short () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtUShort)
        throw IVariantHelperException("Bad cast");
      unsigned short *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const int () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtInt)
        throw IVariantHelperException("Bad cast");
      int *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const unsigned int () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtUInt)
        throw IVariantHelperException("Bad cast");
      unsigned *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const long () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtLong)
        throw IVariantHelperException("Bad cast");
      long *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const unsigned long () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtULong)
        throw IVariantHelperException("Bad cast");
      unsigned long *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const float () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtFloat)
        throw IVariantHelperException("Bad cast");
      float *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const double () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtDouble)
        throw IVariantHelperException("Bad cast");
      double *Value = 0;
      if (GetDataSize() != sizeof(*Value))
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return *Value;
    }
    operator const char* () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtString)
        throw IVariantHelperException("Bad cast");
      char *Value = 0;
      if (!GetDataSize())
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return Value;
    }
    operator const wchar_t* () const
    {
      if (IsEmpty())
        throw IVariantHelperException("Empty variant");
      if (GetType() != IVariant::vtWString)
        throw IVariantHelperException("Bad cast");
      wchar_t *Value = 0;
      if (!GetDataSize())
        throw IVariantHelperException("Bad value");
      if (Var->GetValue(reinterpret_cast<TPtr *>(&Value)) != rcOk)
        throw IVariantHelperException("Can't get value");
      return Value;
    }

    IVariant::VariantType GetType() const
    {
      IVariant::VariantType Type = IVariant::vtUnknown;
      if (Var->GetType(&Type) != rcOk)
        throw IVariantHelperException("Can't get type");
      return Type;
    }
    bool IsEmpty() const
    {
      bool isEmpty = 0;
      if (Var->IsEmpty(&isEmpty) != rcOk)
        throw IVariantHelperException("Can't get flag IsEmpty");
      return isEmpty;
    }
    ULong GetDataSize() const
    {
      ULong Size = 0;
      if (Var->GetValueSize(&Size) != rcOk)
        throw IVariantHelperException("Can't get size");
      return Size;
    }
    IVariantPtr GetVariant() const
    {
      return Var;
    }

  private:
    mutable IVariantPtr Var;
  };

}

#endif  // !__IVARIANT_HELPER_H__
